package com.powerunion.datacollection.report.excelreport.base.element;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.powerunion.datacollection.report.excelreport.Logger;
import com.powerunion.datacollection.report.excelreport.base.BaseElement;
import com.powerunion.datacollection.report.excelreport.base.BaseField;
import com.powerunion.datacollection.report.excelreport.base.IFieldValueListener;
import com.powerunion.datacollection.report.excelreport.base.ITempletContainer;
import com.powerunion.datacollection.report.excelreport.base.Parameter;
import com.powerunion.datacollection.report.excelreport.base.Position;
import com.powerunion.datacollection.report.excelreport.util.AnalyseTempletTool;
import com.powerunion.datacollection.report.excelreport.util.HelpTools;

/**
 * 实现字符类型模板元素,该模板元素将包含的内容生成一个字符串,
 * 并将生成的字符串输出到模板元素定义位置的单元格中.
 * @author juny
 *
 */
public class StringField extends BaseField implements IFieldValueListener{
    private static Logger log = Logger.getLogger(StringField.class);
    public StringField(ITempletContainer container) {
        super(container);
        fieldObjectMap = new HashMap();
    }
    
    /*
     *  (non-Javadoc)
     * @see net.excel.report.base.BaseElement#iniElement()
     */
    public void iniElement() {
        //延迟模板分析，因为当前计算域单元格构建的时候，后面的单元格可能还未生成。
        StringBuffer content = new StringBuffer(fieldContent);
        //获取需要取值的字段变量名称
        this.getDeclareFieldsObject(content);
    }
     
    /*
     * (non-Javadoc)
     * @see net.excel.report.base.BaseElement#setParentContainer(net.excel.report.base.ITempletContainer)
     */
    public void setParentContainer(ITempletContainer parentContainer){
        super.setParentContainer(parentContainer);
        //向包含本计算字段的容器注册监听器，实现延迟计算功能, 
        ((BaseElement)parentContainer).addListener(this);
    }

    public boolean writeImpl(Parameter param) throws Exception {
        if(!isWrite){
            //实现延迟计算，先将参数做一个快照，将计算单元格的位置等信息保存下来,
            this.param = (Parameter)param.clone();
            param.wc = null;
            return false;
        }else{
            //初始化要取值的字段变量
            initFieldObjectWithParam(this.param);
            
            String value = getValue();
            
            if (HelpTools.notEmpty(value) && !value.equals(fieldContent)) {
                this.param.wc = copyDefaultCell(this.param, value);
            } else {
                Position pos = new Position(this.param.wc.getColumn(), this.param.wc.getRow());
                log.error("Fail to get the cell's value. ["
                        + pos.getPositionExcelDec() + "]");
                
                this.param.wc = this.copyDefaultCell(this.param, "");
            }
            
            //延迟计算时需要直接调用sheet来将单元格加入.
            if(null != param.wc){
                param.sheet.addCell(param.wc);
            }
        }
        return true;
    }
    
    /*
     * (non-Javadoc)
     * @see net.excel.report.base.IElementWriter#setElementTempletValue(java.lang.String)
     */
    public void setElementTempletValue(String value) {
        StringBuffer content = new StringBuffer();
        content.append(AnalyseTempletTool.getElementDeclare(value));
        if(AnalyseTempletTool.haveVariableName(content)){
            this.setName(AnalyseTempletTool.getVariableName(content));
        }else{
            this.setName(content.toString());
        }
        //获取需要取值的字段变量名称
        //getDeclareFieldsObject(content);
        //保存当前模板元素的内容
        fieldContent = content.toString();
    }
    
    /**
     * 获取当前模板元素中声明的其他模板元素列表，并生成，或取得对应
     * 模板元素的对象实例。
     * @param content
     */
    private void getDeclareFieldsObject(StringBuffer content){
        fieldNameList = this.getDeclareFields(content);
        if(null == fieldNameList) return;
        
        ITempletContainer ictr = this.getTopContainer();
        BaseElement element = null;
        String fieldName = null;
        String name = null;
        Variable v = null;
        
        
        for(int i=0; i<fieldNameList.size(); i++){
            fieldName = (String)fieldNameList.get(i);
            name = AnalyseTempletTool.getElementName(fieldName);
            
            element = ictr.getElement(name);
            if(null != element){
                //如果是一个模板元素，则需监听模板元素的值，
                element.addListener(this);
                this.fieldObjectMap.put(name, "");
                continue;
            }
            //如果声明的字段不是一个在模板中定义的模板元素，而是一个字段变量。
            v = ElementFactory.getVariableInstances(fieldName);
            if(null != v){
                this.fieldObjectMap.put(name, v);
            }else{
                log.warn("Couldn't create field instance. Field name is " + fieldName);
            }
        }
    }
    
    /**
     * 初始化定义要取值的变量对象
     * @param param
     */
    private void initFieldObjectWithParam(Parameter param){
        Object var = null;
        String name = null;
        //配置相应变量对象的初始化参数。
        for(int i=0; i<this.fieldNameList.size(); i++){
            name = (String)fieldNameList.get(i);
            name = AnalyseTempletTool.getElementName(name);
            
            var = this.fieldObjectMap.get(name);
            
            if(null != var && var instanceof Variable){
                ((Variable)var).setParam(param);
            }
        }
    }
    
    /**
     * 取得当前模板元素的值,将字符串中声明的模板元素的值都取出,并替换.
     * @return
     * @throws Exception 
     */
    private String getValue() throws Exception{
        Object var = null;
        String name = null;
        String value = fieldContent;
        //配置相应变量对象的初始化参数。
        for(int i=0; i<this.fieldNameList.size(); i++){
            name = (String)fieldNameList.get(i);
            
            var = this.fieldObjectMap.get(AnalyseTempletTool.getElementName(name));
            if(null != var) {
                if(var instanceof Variable){   
                    value = HelpTools.replace(value, name, ((Variable)var).getString());
                }else{
                    value = HelpTools.replace(value, name, var.toString());
                }
            }
        }
        return value;
    }
    
    /*
     *  (non-Javadoc)
     * @see net.excel.report.base.IFieldValueListener#setValue(java.lang.String, java.lang.Object, int, int)
     */
    public void setValue(String sourceName, Object value, int col, int row) {
        //默认将监听的值加入列表保存，如果这个函数被调用多次，只保存最后一次
        //该被监听的模板元素的值。
        
        if(null != value){
            if(fieldObjectMap.containsKey(sourceName)){
                fieldObjectMap.put(sourceName, value.toString());
            }
        }
    }

    /*
     *  (non-Javadoc)
     * @see net.excel.report.base.IFieldValueListener#reset()
     */
    public void reset() throws Exception {
        isWrite = true;
        //延迟数据输出
        this.write(this.param);
        isWrite = false;
    }
    
    private Map fieldObjectMap;
    private List fieldNameList;
    private String fieldContent;
    private boolean isWrite = false;
    private Parameter param;
}
